package com.sunxd.zstudy.proxy.asm.test1;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author sun.xd
 * @description: description
 * @date 2023/3/8 9:25
 */
public class CreateClass implements Opcodes {

    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        createClass();
    }

    public static void createClass() throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        ClassWriter cw = new ClassWriter(0);
        //Opcodes.V1_8指定类的版本
        //Opcodes.ACC_PUBLIC表示这个类是public，
        //“test/Person”类的全限定名称
        //第一个null位置变量定义的是泛型签名，
        //“java/lang/Object”这个类的父类
        //第二个null位子的变量定义的是这个类实现的接口
        cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "com/sunxd/asm/Person", null, "java/lang/Object", null);
        ClassVisitor cv = new CreateClassAdapter(cw);
        cv.visitField(ACC_PRIVATE, "name", "Ljava/lang/String;", null, null);
        cv.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null).visitCode();;
        cv.visitMethod(ACC_PUBLIC, "getName", "()Ljava/lang/String;", null, null).visitCode();;
        cv.visitMethod(ACC_PUBLIC, "setName", "(Ljava/lang/String;)V", null, null).visitCode();;
        cv.visitEnd();

        byte[] code = cw.toByteArray();
        MyClassLoader classLoader = new MyClassLoader();
        Class<?> exampleClass = classLoader.definClassFromClassFile("com.sunxd.asm.Person", code);
        for(Method method : exampleClass.getMethods()){
            System.out.println(method);
        }
        System.out.println(exampleClass.getMethod("getName").invoke(exampleClass.newInstance(), null));


    }
    static class MyClassLoader extends ClassLoader {
        public Class definClassFromClassFile(String className, byte[] classFile)
                throws ClassFormatError {
            return defineClass(className, classFile, 0, classFile.length);
        }
    }
}
